#include "stdafx.h"
#include "AsyncSocket.h"

#include "Define.h"


namespace Util
{
	AsyncSocket::AsyncSocket()
	{
		mSock = INVALID_SOCKET;
	}

	AsyncSocket::~AsyncSocket()
	{
		Close();
	}

	BOOL AsyncSocket::Connect(LPCSTR host, USHORT port)
	{
		_init_wsa();

		mSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		int sz = 64 * 1024;
		setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, (char*)&sz, sizeof(int));
		setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, (char*)&sz, sizeof(int));

		int ret = SOCKET_ERROR;

		sockaddr_in sin;
		sin.sin_family = AF_INET;
		sin.sin_port = ::htons(port);
		sin.sin_addr.S_un.S_addr = inet_addr(host);
		ret = ::connect(mSock, (sockaddr *)&sin, sizeof(sin));

		if (ret == SOCKET_ERROR)
		{
			ErrorLog("Connect Error: " << ::WSAGetLastError());
			return FALSE;
		}
		else
		{
			return TRUE;
		}
	}

	BOOL AsyncSocket::SetTimeOut(int sec)
	{
		if (mSock != INVALID_SOCKET)
		{
			DWORD dwTimeout = sec * 1000;
			int iResult = setsockopt(mSock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&dwTimeout, sizeof(DWORD));
			if (iResult == SOCKET_ERROR)
			{
				ErrorLog("SetTimeOut Error: " << ::WSAGetLastError());
				return FALSE;
			}
			iResult = setsockopt(mSock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&dwTimeout, sizeof(DWORD));
			if (iResult == SOCKET_ERROR)
			{
				ErrorLog("SetTimeOut Error: " << ::WSAGetLastError());
				return FALSE;
			}
		}
		return TRUE;
	}

	BOOL AsyncSocket::Send(const char* buf, int size)
	{
		int totalLen = 0;

		do
		{
			int len = ::send(mSock, buf + totalLen, size - totalLen, 0);
			if (len == SOCKET_ERROR)
			{
				totalLen = SOCKET_ERROR;
			}
			else
			{
				totalLen += len;
			}
		} while (totalLen != SOCKET_ERROR && totalLen < size);

		if (totalLen == SOCKET_ERROR)
			return FALSE;
		else
			return TRUE;
	}


	BOOL AsyncSocket::Recv(char* buf, int& size)
	{
		BOOL rst = FALSE;

		int iResult = 0;
		iResult = ::recv(mSock, buf, size, 0);
		if (iResult > 0)
		{
			size = iResult;
			rst = TRUE;
		}
		else if (iResult == 0)
		{
			size = 0;
			rst = FALSE;
		}
		else
		{
			size = 0;
			rst = FALSE;
		}

		return rst;
	}


	void AsyncSocket::Close()
	{
		if (mSock != INVALID_SOCKET)
		{
			::shutdown(mSock, SD_BOTH);
			::closesocket(mSock);
		}
		mSock = INVALID_SOCKET;
	}

	void AsyncSocket::_init_wsa()
	{
		static bool bInitFlg = false;
		if (!bInitFlg)
		{
			WSADATA wsaData;
			int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
			if (iResult != 0) {
				printf("WSAStartup failed with error: %d\n", iResult);
			}

			bInitFlg = true;
		}
	}
}